package com.amigo.online.message.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.amigo.online.message.entity.ChatMessage;
import com.amigo.online.message.enums.MessageCallbackEnum;
import com.amigo.online.message.mapper.message.MessageTblMapper;
import com.amigo.online.message.mapper.online.GroupTblMapper;
import com.amigo.online.message.mapper.online.UserTblMapper;
import com.amigo.online.message.mybatisbean.GroupTbl;
import com.amigo.online.message.mybatisbean.MessageTbl;
import com.amigo.online.message.mybatisbean.UserTbl;
import com.amigo.online.message.proto.IMBaseDefine;
import com.amigo.online.message.service.MessageCallbackService;
import com.amigo.online.message.util.ChatMessageDecoder;
import com.amigo.online.message.util.onesignal.OneSignalUtil;
import com.google.protobuf.InvalidProtocolBufferException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.data.redis.core.HyperLogLogOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Base64;
import java.util.Date;
import java.util.regex.Pattern;

@Service
@Slf4j
public class MessageCallbackServiceImpl implements MessageCallbackService {

    @Autowired
    RedisTemplate<String, String> redisTemplate;
    @Autowired
    MessageTblMapper messageTblMapper;
    @Autowired
    OneSignalUtil oneSignalUtil;
    @Autowired
    UserTblMapper userTblMapper;
    @Autowired
    GroupTblMapper groupTblMapper;

    private ChatMessageDecoder decoder= new ChatMessageDecoder();
    @SuppressWarnings("all")
    public void callback(ChatMessage chatMessage){
        String payload = chatMessage.getPayload();
        byte[] bytes = Base64.getDecoder().decode(payload);
        ByteBuffer buffer=ByteBuffer.wrap(bytes);
        buffer.order(ByteOrder.BIG_ENDIAN);

        short sid = buffer.getShort(8);
        short cid = buffer.getShort(10);
        byte[] body = new byte[bytes.length-16];
        System.arraycopy(bytes,16,body,0,bytes.length-16);
        IMBaseDefine.ServiceID serviceID = IMBaseDefine.ServiceID.forNumber(sid);
        MessageTbl messageTbl = null;
        switch (serviceID){
            case SID_MSG:
                try {
                    messageTbl = decoder.decoder(cid,body);
                    messageTbl.setId(chatMessage.getSequence());
                    messageTbl.setImtype(chatMessage.getMsgType());
                } catch (InvalidProtocolBufferException e) {
                    e.printStackTrace();
                }
                break;
            case SID_NOTICE:
                break;
        }
        if(messageTbl == null){
            return;
        }
        if(chatMessage.getTimestamp().getTime()>new Date().getTime() - (30*1000)){//30秒前的消息不推送
            //发送通知
            sendNotice(chatMessage,messageTbl);
        }
        try {
            messageTblMapper.insert(messageTbl);
        }catch (DuplicateKeyException e){
            String importFileRole = "Duplicate entry '\\d*' for key 'PRIMARY'";//正则表达式
            //如果不是Duplicate entry '\d*' for key 'PRIMARY'(主键冲突)异常跑去抛出异常
            if (!Pattern.matches(importFileRole, e.getCause().getMessage())){
                log.error("" , e);
                throw e;
            }else {
                log.debug("主键冲突：" + chatMessage.getSequence());
            }
        }

    }
    public static void main(String[] args) {
        System.out.println(new Date().getTime());
        System.out.println(new Date().getTime() - (3*60*1000));
    }
    /**
     * 发送通知
     * @param chatMessage
     * @param messageTbl
     */
    private void sendNotice(ChatMessage chatMessage, MessageTbl messageTbl){
//        如果是离线消息
        if(chatMessage.getMsgType().equals(MessageCallbackEnum.OFFLINE_MSG.getMsgType())) {//单聊离线消息
            sendNotice(chatMessage.getSequence(),messageTbl, "",messageTbl.getToUid());
        }else if(chatMessage.getMsgType().equals(MessageCallbackEnum.OFFLINE_TOPIC_MSG.getMsgType())){//群聊离线消息
            UserTbl userTbl = userTblMapper.selectByPrimaryKey(messageTbl.getFromUid());
            sendNotice(chatMessage.getSequence(),messageTbl, userTbl.getNickname() + ": ", chatMessage.getToAccounts());
        }
    }

    /**
     * 发送通知
     * @param chatMessageSequence im消息ID
     * @param messageTbl
     * @param userId 接收通知的userid
     */
    private void sendNotice(long chatMessageSequence, MessageTbl messageTbl, String headLong, Long... userId){
        try {
            //发送通知
            HyperLogLogOperations hyperLogLogOperations = redisTemplate.opsForHyperLogLog();
            long boo = hyperLogLogOperations.add("callbackOneSignal", String.valueOf(chatMessageSequence));
            String heading = "";
            if(messageTbl.getSessionType() == 1){//单聊
                heading = messageTbl.getFromNickname();
            }else if(messageTbl.getSessionType() == 2){//群聊
                Long groupId = messageTbl.getToUid();
                GroupTbl groupTbl =  groupTblMapper.selectByPrimaryKey(groupId);
                heading = groupTbl.getName();
            }else {
                log.info("消息类型不对: ", messageTbl);
                return;
            }

            if(boo!=0){
                switch ( messageTbl.getType()){//文本消息
                    case 1:
                        oneSignalUtil.sendByUserId(heading,headLong + messageTbl.getContent(), userId);
                        break;
                    case 2://图片消息
                        JSONObject jsonObject = new JSONObject();
                        jsonObject.put("en",headLong + "[image]");
                        jsonObject.put("zh-Hans",headLong + "[图片]");
                        jsonObject.put("pt",headLong + "[imagem]");
                        oneSignalUtil.sendByUserId(heading, jsonObject, userId);
                        break;
                    case 3://语音消息
                        JSONObject jsonObject3 = new JSONObject();
                        jsonObject3.put("en",headLong + "[voice]");
                        jsonObject3.put("zh-Hans",headLong + "[语音]");
                        jsonObject3.put("pt",headLong + "[voz]");
                        oneSignalUtil.sendByUserId(heading, jsonObject3, userId);
                        break;
                    case 4://视频
                        JSONObject jsonObject4 = new JSONObject();
                        jsonObject4.put("en",headLong + "[video]");
                        jsonObject4.put("zh-Hans",headLong + "[视频]");
                        jsonObject4.put("pt",headLong + "[vídeo]");
                        oneSignalUtil.sendByUserId(heading, jsonObject4, userId);
                        break;
                    case 5://位置
                        JSONObject jsonObject5 = new JSONObject();
                        jsonObject5.put("en",headLong + "[position]");
                        jsonObject5.put("zh-Hans",headLong + "[位置]");
                        jsonObject5.put("pt",headLong + "[posição]");
                        oneSignalUtil.sendByUserId(heading, jsonObject5, userId);
                        break;
                }
            }
        } catch (Exception e) {
            log.error("通知发送失败", e);
            throw  e;
        }
    }

}
